package com.warm.spring.aop;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description 切面(英雄选择好后, 游戏开始)
 * @Author iyb-liangchuang
 * @Date 2021/5/13 15:33
 */
//@Component
//@Aspect
public class PlayAspect {

    /**
     * PointCut:
     *   用于将 Advice 定向到特定的类和方法
     */
    /**
     * way one set pointcut : use Annotation
     */
    /*@Pointcut("@annotation(com.warm.demo.annotation.Anno)")
    public void pointCut(){
    }*/

    /**
     * way two set pointcut : use pointcut expression
     * 切点命名:
     *   命名切点仅仅使用方法名及访问修饰符的信息, 一般定义方法的返回类型为void, 方法体为空
     */
    @Pointcut("execution(* com..ioc.Equipment.use(..))")
    public void pointCut(){
    }

    /**
     * 在切点方法之前执行
     * @param joinPoint
     */
    @Before(value = "pointCut()")
    public void doBefore(JoinPoint joinPoint){
        System.out.println("executing in pointCut method before");
    }

    /**
     * 在切点方法之后执行
     * @param joinPoint : 作为函数的参数传入切面方法，可以得到目标方法的相关信息
     */
    @After(value = "pointCut()")
    public void doAfter(JoinPoint joinPoint){
        System.out.println("executing in pointCut method after");
    }

    /**
     * 切点方法返回后执行
     *    1. 第一个参数为JoinPoint, 第二个参数为返回值的信息
     *    2. 第一个参数不为JoinPoint, 第一个参数为returning 中对应的参数
     *    returning: 限定了只有目标方法返回值与通知方法参数类型匹配时才能执行后置返回通知
     *               ，否则不执行，参数为Object类型将匹配任何目标返回值
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void doAfterReturn(JoinPoint joinPoint, Object result){
        System.out.println("executing in pointCut method return after");
        System.out.println("return Result!");
    }

    /**
     * 切点方法抛异常执行
     *    定义一个名字，该名字用于匹配通知实现方法的一个参数名，当目标方法抛出异常返回后，将把目标方法抛出的异常传给通知方法；
     *    throwing:限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知，否则不执行，
     *    对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
     * @param joinPoint
     * @param exception
     */
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void doAfterThrow(JoinPoint joinPoint, Throwable exception){
        System.out.println("executing in pointCut method throw after");
    }

    /**
     *
     * 属于环绕增强，能控制切点执行前，执行后，，用这个注解后，程序抛异常，会影响@AfterThrowing这个注解
     *
     * org.aspectj.lang.JoinPoint 接口表示目标类连接点对象，它定义这些主要方法。
     * Object[] getArgs()：获取连接点方法运行时的入参列表。
     * Signature getSignature()：获取连接点的方法签名对象。
     * Object getTarget()：获取连接点所在的目标对象。
     * Object getThis()：获取代理对象。
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around(value = "pointCut()")
    public Object doAroud(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("pointCut method around start");
        Object[] args = pjp.getArgs();
        Object o = pjp.proceed(args);
        System.out.println("pointCut method around end");
        return o;
    }
}
